///////////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
#include <Shader/GPUProgram.h>
//#include <Shader/ShaderManager.h>
#include <Texture/TextureManager.h>
#include <Texture/Texture.h>
#include <File/LocalFile.h>
#include <tinyxml.h>

//-----------------------------------------------------------------------------

GPUProgram::GPUProgram()
{
	//ShaderManager::GetInstance()->AddShader( this );
	m_inUse = false;
}

//-----------------------------------------------------------------------------

bool		GPUProgram::IsThisShader(std::string filename)
{
	return filename == m_filename;
}

//-----------------------------------------------------------------------------

void		GPUProgram::SetFilename(std::string filename)
{
	m_filename = filename;
}

//-----------------------------------------------------------------------------

std::string	GPUProgram::GetFilename()
{
	return m_filename;
}

//-----------------------------------------------------------------------------

void		GPUProgram::ParseElement(TiXmlElement* elem)
{
	if( elem )
	{
		ASSERT( !strcmp( elem->Value(), "shader" )  );
		TiXmlElement* node = NULL;

		LocalFile* vertexFile = NULL;
		LocalFile* fragmentFile = NULL;

		std::string	vertexMain = "";
		std::string	fragmentMain = "";

		std::string	vertexArgs = "";
		std::string	fragmentArgs = "";

		std::string filename = "";

		node = elem->FirstChildElement( "vertex" );
		if( node )
		{
			if( node->Attribute( "file" ) )
			{
				filename = node->Attribute( "file" );
			}
			else
			{
				filename = "";
				DEBUG_ERR("[GPUProgram::ParseElement] Did not specify vertex file!\n");
			}
			vertexFile = MGL_NEW LocalFile( filename.c_str() );
			if( !vertexFile || !vertexFile->IsOpen() )
			{
				DEBUG_ERR("[GPUProgram::ParseElement] Could not open file '%s'!\n", filename.c_str() );
			}

			if( node->Attribute( "main" ) )
			{
				vertexMain = node->Attribute( "main" );
			}
			if( node->Attribute( "args" ) )
			{
				vertexArgs = node->Attribute( "args" );
			}
		}

		node = elem->FirstChildElement( "fragment" );
		if( node )
		{
			if( node->Attribute( "file" ) )
			{
				filename = node->Attribute( "file" );
			}
			else
			{
				filename = "";
				DEBUG_ERR("[GPUProgram::ParseElement] Did not specify fragment file!\n");
			}
			fragmentFile = MGL_NEW LocalFile( filename.c_str() );
			if( !fragmentFile || !fragmentFile->IsOpen() )
			{
				DEBUG_ERR("[GPUProgram::ParseElement] Could not open file '%s'!\n", filename.c_str() );
			}

			if( node->Attribute( "main" ) )
			{
				fragmentMain = node->Attribute( "main" );
			}
			if( node->Attribute( "args" ) )
			{
				fragmentArgs = node->Attribute( "args" );
			}
		}

		node = elem->FirstChildElement( "texture" );
		while( node )
		{
			std::string param = "";
			std::string name = "";
			u8	unit = 0;

			if( node->Attribute( "param" ) )
			{
				param = node->Attribute( "param" );
			}
			if( node->Attribute( "unit" ) )
			{
				u32 u = 0;
				sscanf( node->Attribute( "unit" ), "%u", &u );
				unit = u;
			}
			if( node->Attribute( "name" ) )
			{
				name = node->Attribute( "name" );
			}

			if( m_textureMap.find( unit ) == m_textureMap.end() )
			{
				m_textureMap[ unit ] = param;
				if( name.size() )
				{
					m_textureMapSearch[ unit ] = name;
				}
			}
			else
			{
				DEBUG_WAR( "[GPUProgram::ParseElement] Texture unit already used '%d'!\n", unit );
			}

			node = node->NextSiblingElement( "texture" );
		}

		Load( vertexFile, fragmentFile, vertexMain.c_str(), fragmentMain.c_str(), vertexArgs.c_str(), fragmentArgs.c_str() );

		SAFE_DEL( vertexFile );
		SAFE_DEL( fragmentFile );

		Compile();
		Link();
		Validate();
		LoadParameters();
	}
}

//-----------------------------------------------------------------------------

std::string		GPUProgram::GetParamNameForTextureUnit(u8 unit)
{
	std::map<u8, std::string>::iterator it = m_textureMap.find( unit );
	std::set<u8>::iterator tmpit;
	if( it != m_textureMap.end() )
	{
		tmpit = m_textureBind.find( it->first );
		if( tmpit != m_textureBind.end() )
		{
			m_textureBind.erase( tmpit );
		}
		return it->second;
	}

	return std::string("");
}

//-----------------------------------------------------------------------------

void	GPUProgram::BeginTextureBind()
{
	m_textureBind.clear();
	std::map<u8, std::string>::iterator it = m_textureMapSearch.begin();;
	while( it != m_textureMapSearch.end() )
	{
		m_textureBind.insert( it->first );
		it++;
	}
}

//-----------------------------------------------------------------------------

void	GPUProgram::EndTextureBind()
{
	std::set<u8>::iterator it = m_textureBind.begin();
	while( it != m_textureBind.end() )
	{
		Texture *tex = TextureManager::GetInstance()->GetTexture( m_textureMapSearch[ *it ] );
		if( tex )
		{
			tex->bind( GL_TEXTURE0 + *it );
			SetParameterTexture( m_textureMap[ *it ].c_str(), tex->GetTextureId(), *it );
		}
		it++;
	}
}

//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
